package com.smartwheel.web.controller;

import com.smartwheel.db.DbManager;
import com.smartwheel.model.dto.TripEntryDTO;
import com.sw.model.Point;
import com.sw.render.TileRender;
import com.sw.render.png.PngTileRender;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Controller
@RequestMapping("/data-store")
public class JSONController {

    private static final Logger LOG = LoggerFactory.getLogger(JSONController.class);

    @Resource(name = "dbManager")
    protected DbManager dbManager;

    @Resource
    private ServletContext servletContext;

    private TileRender tileRender = new PngTileRender();

    @RequestMapping("/mock")
    @ResponseBody
    public List<TripEntryDTO> getMockEntries() {
        return generateMockEntries(25);
    }

    @RequestMapping("/ts/{startTs}/{endTs}")
    @ResponseBody
    public String fetchTripEntries(@PathVariable Long startTs, @PathVariable Long endTs) {
        LOG.debug("Fetching entries from startTs=[" + startTs + "], endTs=[" + endTs + "]");
        return dbManager.get(startTs, endTs);
    }

    @RequestMapping(value = "/store", method = RequestMethod.POST)
    @ResponseBody
    public String storeTripEntries(HttpServletRequest request) {
        TripEntryDTO entry;
        try {
            String rawJSonData = request.getParameter("data");
            LOG.debug("Storing raw=\n[" + rawJSonData + "]");
            entry = convertToEntry(rawJSonData);

            dbManager.storeObject(rawJSonData);
//            String rawJsonList = request.getParameter("data-list");
//
//            if (rawJsonList != null && !rawJsonList.isEmpty()) {
//                dbManager.storeList(rawJsonList);
//            }
        } catch (Exception ex) {
            LOG.error("Some error occurred when storing data.", ex);
            return "ERROR";
        }

        try {
            displayContentBody(request.getReader());
        } catch (IOException e) {
            LOG.error("Could not read stream", e);
        }

        String realPath = servletContext.getRealPath("/img/tiles/");
        LOG.debug("path=[" + realPath + "]");
        createTile(entry, realPath);
        return "OK";
    }

    private void displayContentBody(BufferedReader reader) {
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                LOG.debug("REQUEST-LINE" + line);
            }
        } catch (IOException e) {
            LOG.error("Reading stream", e);
        }
    }

    private void createTile(TripEntryDTO entry, String realPath) {
        if (entry != null) {
            try {
                Double lat = entry.getLat();
                Double lon = entry.getLon();
                Double speed = entry.getSpeed();
                Point point = new Point(entry.getUid(), lat, lon, speed, entry.getFuel());
                tileRender.renderTile(point, realPath);
            } catch (Exception ex) {
                LOG.error("Could not create tile", ex);
            }
        }
    }

    private TripEntryDTO convertToEntry(String rawJSonData) {
        ObjectMapper mapper = new ObjectMapper();
        TripEntryDTO tripEntryDTO = null;
        try {
            tripEntryDTO = mapper.readValue(rawJSonData, TripEntryDTO.class);
        } catch (IOException e) {
            LOG.error("Some problem occurred when parsing json!", e);
        }
        return tripEntryDTO;
    }

    private List<TripEntryDTO> generateMockEntries(int total) {
        ArrayList<TripEntryDTO> mockDataList = new ArrayList<TripEntryDTO>();
        long currentTimestamp = System.currentTimeMillis();
        for (int i = 0; i < total; i++) {
            TripEntryDTO e = generateTripEntry(i, currentTimestamp);
            mockDataList.add(e);
        }

        return mockDataList;
    }

    private TripEntryDTO generateTripEntry(int i, long currentTimestamp) {
        TripEntryDTO tripEntryDTO = new TripEntryDTO();
        tripEntryDTO.setId(String.valueOf(i));
        tripEntryDTO.setRpm((long) getRandomInt(1500, 6000));
        tripEntryDTO.setLat(46.7693367 - (i / 10000));
        tripEntryDTO.setLon(23.6105634 - (i / 10000));
        tripEntryDTO.setFuel(4 + getRandomDouble(0, 5D));
        tripEntryDTO.setSpeed(getRandomDouble(40, 120));
        tripEntryDTO.setTs(currentTimestamp - (i * 1000));
        tripEntryDTO.setUid("dragos1");
        return tripEntryDTO;
    }

    private double getRandomDouble(double low, double high) {
        return low + (new Random().nextDouble() * high);
    }

    private int getRandomInt(int low, int high) {
        return high - new Random().nextInt(low);
    }

}